﻿using System;
using System.Collections.Generic;
using Teigha.DatabaseServices;
using Teigha.Geometry;

namespace SRB.Tg.DrawingStandard
{
    public static class Extensions
    {
        public static string curTKPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "Template\\TK.dwg";
        public static string curMapSheet = "A3";
        public static string curFont = "SRB.HT";
        public static string Font = "仿宋";
        public static double FontWidth = 0.7;
        public static double bottomHeight = 20;
        public static double leftWidth = 30;
        public static double topHeight = 10;
        public static double rightWidth = 15;
        public static string scaleList = "1,5,8,15,20,50,75,80,100,125,150,200,300";
        public static string modelunit = "mm";
        public static string layoutunit = "cm";
        public static string curAppPath = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "Template\\";

        public static void ChangeValues(string curTKPath,double bottomHeight, double leftWidth, double topHeight, double rightWidth, string scaleList = "1,5,8,15,20,50,75,80,100,125,150,200,300")
        {
            if (!string.IsNullOrEmpty(curTKPath)) 
            {
                Extensions.curTKPath = curTKPath;
            }
            //Extensions.curMapSheet = curMapSheet;
            //Extensions.curFont = curFont;
            //Extensions.Font = Font;
           // Extensions.FontWidth = FontWidth;
            Extensions.bottomHeight = bottomHeight;
            Extensions.leftWidth = leftWidth;
            Extensions.topHeight = topHeight;
            Extensions.rightWidth = rightWidth;
            if (!string.IsNullOrEmpty(scaleList))
            {
                Extensions.scaleList = scaleList;
            }
            //Extensions.modelunit = modelunit;
            //Extensions.layoutunit = layoutunit;
            //Extensions.curAppPath = curAppPath;
        }


        #region Extents2d扩展
        /// <summary>
        /// 获取中心点
        /// </summary>
        /// <param name="ext"></param>
        /// <returns></returns>
        public static Point2d GetCenter(this Extents2d ext)
        {
            return new Point2d((ext.MinPoint.X + ext.MaxPoint.X) * 0.5, (ext.MinPoint.Y + ext.MaxPoint.Y) * 0.5);
        }
        /// <summary>
        /// 获取均分点
        /// </summary>
        /// <param name="ext"></param>
        /// <param name="num">第几份</param>
        /// <param name="all">多少份数</param>
        /// <returns></returns>
        public static Point2d GetDivCenter(this Extents2d ext, int num, int all)
        {
            return new Point2d((ext.MinPoint.X + (ext.MaxPoint.X - ext.MinPoint.X) * (num - 1) / all + (ext.MaxPoint.X - ext.MinPoint.X) / all * 0.5), (ext.MinPoint.Y + ext.MaxPoint.Y) * 0.5);
        }

        /// <summary>
        /// 获取均分点
        /// </summary>
        /// <param name="ext"></param>
        /// <param name="num">第几份</param>
        /// <param name="all">多少份数</param>
        /// <returns></returns>
        public static Point2d GetDivMax(this Extents2d ext, int num, int all)
        {
            return new Point2d((ext.MinPoint.X + (ext.MaxPoint.X - ext.MinPoint.X) * ((double)num / all)), ext.MaxPoint.Y);
        }
        /// <summary>
        /// 获取均分点
        /// </summary>
        /// <param name="ext"></param>
        /// <param name="num">第几份</param>
        /// <param name="all">多少份数</param>
        /// <returns></returns>
        public static Point2d GetDivMin(this Extents2d ext, int num, int all)
        {
            return new Point2d((ext.MinPoint.X + (ext.MaxPoint.X - ext.MinPoint.X) * ((double)(num-1) / all)), ext.MinPoint.Y);
        }
        /// <summary>
        /// Extents2d宽度
        /// </summary>
        /// <param name="ext"></param>
        /// <returns></returns>
        public static double W(this Extents2d ext)
        {
            return ext.MaxPoint.X - ext.MinPoint.X;
        }
        /// <summary>
        /// Extents2d长度
        /// </summary>
        /// <param name="ext"></param>
        /// <returns></returns>
        public static double L(this Extents2d ext)
        {
            return ext.MaxPoint.Y - ext.MinPoint.Y;
        }
        /// <summary>
        /// Extents2d转Polyline
        /// </summary>
        /// <param name="ext"></param>
        /// <returns></returns>
        public static Polyline ConvertPL(this Extents2d ext)
        {
            Polyline pl = new Polyline() { Closed = true };
            pl.AddVertexAt(0, ext.MinPoint, 0, 0, 0);
            pl.AddVertexAt(1, ext.MinPoint.C2D(0, ext.MaxPoint.Y - ext.MinPoint.Y), 0, 0, 0);
            pl.AddVertexAt(2, ext.MaxPoint, 0, 0, 0);
            pl.AddVertexAt(3, ext.MinPoint.C2D(ext.MaxPoint.X - ext.MinPoint.X, 0), 0, 0, 0);
            return pl;
        }
        /// <summary>
        /// Extents2d运算
        /// </summary>
        /// <param name="ori"></param>
        /// <param name="other"></param>
        /// <returns></returns>
        public static Extents2d Add(this Extents2d ori, Extents2d other)
        {
            double minX = Math.Min(ori.MinPoint.X, other.MinPoint.X);
            double minY = Math.Min(ori.MinPoint.Y, other.MinPoint.Y);
            double maxX = Math.Max(ori.MaxPoint.X, other.MaxPoint.X);
            double maxY = Math.Max(ori.MaxPoint.Y, other.MaxPoint.Y);
            return new Extents2d(minX, minY, maxX, maxY);
        }

        /// <summary>
        /// 转化为2d，取消z
        /// </summary>
        /// <param name="ori"></param>
        /// <returns></returns>
        public static Extents2d C2D(this Extents3d ori)
        {
            return new Extents2d(ori.MinPoint.C2D(), ori.MaxPoint.C2D());
        }

        #endregion

        #region  坐标扩展
        /// <summary>
        /// Point3d转Point2d
        /// </summary>
        /// <param name="theP3d"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static Point2d C2D(this Point3d theP3d, double x = 0, double y = 0)
        {
            return new Point2d(theP3d.X + x, theP3d.Y + y);
        }

        /// <summary>
        /// Point3d转Point3d
        /// </summary>
        /// <param name="theP3d"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <param name="z"></param>
        /// <returns></returns>
        public static Point3d C3D(this Point3d theP3d, double x = 0, double y = 0, double z = 0)
        {
            return new Point3d(theP3d.X + x, theP3d.Y + y, theP3d.Z + z);
        }
        /// <summary>
        /// Vector2d转Vector3d
        /// </summary>
        /// <param name="theV2d"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static Vector3d C3D(this Vector2d theV2d, double x = 0, double y = 0)
        {
            return new Vector3d(theV2d.X + x, theV2d.Y + y, 0);
        }
        /// <summary>
        /// Point2d转Point3d
        /// </summary>
        /// <param name="theP2d"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static Point3d C3D(this Point2d theP2d, double x = 0, double y = 0)
        {
            return new Point3d(theP2d.X + x, theP2d.Y + y, 0);
        }
        /// <summary>
        /// Point2d转Point2d
        /// </summary>
        /// <param name="theP2d"></param>
        /// <param name="x"></param>
        /// <param name="y"></param>
        /// <returns></returns>
        public static Point2d C2D(this Point2d theP2d, double x = 0, double y = 0)
        {
            return new Point2d(theP2d.X + x, theP2d.Y + y);
        }
        #endregion

        #region 线扩展
        /// <summary>
        /// 获取一点与多线距离最近的线上点
        /// </summary>
        /// <param name="PL"></param>
        /// <param name="other"></param>
        /// <returns></returns>
        public static Point3d GetClosestVertexTo(this Polyline PL, Point3d other)
        {
            List<Point3d> VS = new List<Point3d>();
            for (int i = 0; i < PL.NumberOfVertices; i++)
            {
                VS.Add(PL.GetPoint3dAt(i));

            }
            VS.Sort((x, y) => x.DistanceTo(other).CompareTo(y.DistanceTo(other)));
            return VS[0];
        }
        /// <summary>
        /// Line2d 转 Line3d
        /// </summary>
        /// <param name="theL2d"></param>
        /// <returns></returns>
        public static Line3d C3D(this Line2d theL2d)
        {
            return new Line3d(theL2d.StartPoint.C3D(), theL2d.EndPoint.C3D());
        }

        public static Line CLine(this Line2d theL2d)
        {
            return new Line(theL2d.StartPoint.C3D(), theL2d.EndPoint.C3D());
        }

        public static Line CLine(this LineSegment2d theL2d)
        {
            return new Line(theL2d.StartPoint.C3D(), theL2d.EndPoint.C3D());
        }
        /// <summary>
        /// 获得对称
        /// </summary>
        /// <param name="thePline">多线名称</param>       
        /// <param name="axis">对称轴</param>       
        public static Polyline GetMirror(this Polyline thePline, Line2d axis)
        {
            Polyline res = (Polyline)thePline.Clone();
            res.TransformBy(Matrix3d.Mirroring(axis.C3D()));
            return res;
        }


        /// <summary>
        /// 线向边界延伸/切割
        /// </summary>
        /// <param name="theLine"></param>
        /// <param name="BD1"></param>
        /// <param name="BD2"></param>
        /// <returns></returns>
        public static Line UpdateBoundary(this Line theLine, Curve BD1, Curve BD2)
        {
            Point3d St = theLine.StartPoint;
            Point3d Ed = theLine.EndPoint;

            Point3dCollection res = new Point3dCollection();
            if (BD1 != null)
            {
                theLine.IntersectWith(BD1, Intersect.ExtendThis, res, 0, 0);

                if (res.Count == 1)
                {
                    St = res[0];
                }
                else if (res.Count == 2)
                {
                    if (res[0].DistanceTo(Ed) < res[1].DistanceTo(Ed))
                    {
                        St = res[0];
                    }
                    else
                    {
                        St = res[1];
                    }
                }
            }

            if (BD2 != null)
            {
                res = new Point3dCollection();

                theLine.IntersectWith(BD2, Intersect.ExtendThis, res, 0, 0);


                if (res.Count == 1)
                {
                    Ed = res[0];
                }
                else if (res.Count == 2)
                {
                    if (res[0].DistanceTo(St) < res[1].DistanceTo(St))
                    {
                        Ed = res[0];
                    }
                    else
                    {
                        Ed = res[1];
                    }
                }
            }
            Line ret = new Line(St, Ed);
            ret.Layer = theLine.Layer;
            return ret;
        }

        #endregion

        #region 字体扩展

        /// <summary>
        /// 根据字体样式ID获取字宽系数
        /// </summary>
        /// <param name="TextStyleID">字体样式ID</param>
        /// <returns></returns>
        public static double GetXScale(this ObjectId TextStyleID)
        {
            //Database acCurDb = HostApplicationServices.WorkingDatabase;
            Database acCurDb = TextStyleID.Database;
            using (Transaction tr = acCurDb.TransactionManager.StartTransaction())
            {
                try
                {
                    TextStyleTableRecord str = (TextStyleTableRecord)tr.GetObject(TextStyleID, OpenMode.ForRead);
                    return str.XScale;
                }
                catch (Exception e) 
                {                 
                    throw e;
                }
            }


        }



        public static double GetWidth(this DBText dbtext)
        {
            if (string.IsNullOrEmpty(dbtext.TextString)) return 0;
            double a = Math.Abs(dbtext.GeometricExtents.MaxPoint.Y - dbtext.GeometricExtents.MinPoint.Y);
            double b = Math.Abs(dbtext.GeometricExtents.MaxPoint.X - dbtext.GeometricExtents.MinPoint.X);
            double angle = new Vector2d(Math.Abs(Math.Cos(dbtext.Rotation)), Math.Abs(Math.Sin(dbtext.Rotation))).GetAngleTo(Vector2d.XAxis);
            double[] t = new double[9]
            {
                 Math.Sin(angle),Math.Cos(angle),0,
                 Math.Cos(angle),Math.Sin(angle),0,
                 0,0,1
            };
            Matrix2d mat = new Matrix2d(t);
            Vector2d vec = mat.Inverse() * new Vector2d(a, b);
            return Math.Abs(vec.X);
        }
        public static double GetHeight(this DBText dbtext)
        {
            if (string.IsNullOrEmpty(dbtext.TextString)) return 0;
            double a = Math.Abs(dbtext.GeometricExtents.MaxPoint.Y - dbtext.GeometricExtents.MinPoint.Y);
            double b = Math.Abs(dbtext.GeometricExtents.MaxPoint.X - dbtext.GeometricExtents.MinPoint.X);
            double angle = new Vector2d(Math.Abs(Math.Cos(dbtext.Rotation)), Math.Abs(Math.Sin(dbtext.Rotation))).GetAngleTo(Vector2d.XAxis);
            double[] t = new double[9]
            {
                 Math.Sin(angle),Math.Cos(angle),0,
                 Math.Cos(angle),Math.Sin(angle),0,
                 0,0,1
            };
            Matrix2d mat = new Matrix2d(t);
            Vector2d vec = mat.Inverse() * new Vector2d(a, b);
            return Math.Abs(vec.Y);
        }

        #endregion



        public static void Add(this DBObjectCollection theCol, DBObjectCollection other)
        {
            foreach (DBObject item in other)
            {
                theCol.Add(item);
            }
        }


        public static ObjectId GetLayoutId(this Database db, string name)
        {
            ObjectId layoutId = new ObjectId();
            BlockTable bt = db.BlockTableId.GetObject(OpenMode.ForRead) as BlockTable;
            foreach (ObjectId btrId in bt)
            {
                BlockTableRecord btr = (BlockTableRecord)btrId.GetObject(OpenMode.ForRead);
                if (btr.IsLayout)
                {
                    Layout layout = (Layout)btr.LayoutId.GetObject(OpenMode.ForRead);
                    if (layout.LayoutName.CompareTo(name) == 0)
                    {
                        layoutId = btr.LayoutId;
                        break;
                    }
                }
            }
            return layoutId;
        }


    }
}
